#!/bin/bash
#
# 静态测试脚本
#
# 用法：$0 <datadir> <timelimit> <chrootdir> <workdir> <run-uuid> <run> <compare> <program args> <source files> <assist files>
#
# <datadir>      此程序不使用数据
# <timelimit>    此程序受 SCRIPTTIMELIMIT 时限限制
# <chrootdir>    子环境
# <workdir>      程序的工作文件夹，为了保证安全，请务必将运行路径设置
#                为空文件夹，特别是保证不可以包含标准输出文件
# <run-uuid>     运行的 uuid，用于索引运行文件夹位置
# <run>          此项将被忽略，此程序不使用运行脚本
# <compare>      此项将被忽略，此程序不使用比较脚本
# <source-files> 源文件集，使用 : 隔开，如 a.cpp:b.cpp
# <assist-files> 头文件集，使用 : 隔开，如 a.hpp:b.hpp
#
# 必须包含的环境变量：
#   RUNGUARD     runguard 的路径
#   RUNUSER      选手程序运行的账户
#   RUNGROUP     选手程序运行的账户组
#
# 可选环境变量
#   MEMLIMIT     运行内存限制，单位为 KB
#   PROCLIMIT    进程数限制
#   FILELIMIT    文件写入限制，单位为 KB

# 导入比较脚本，功能是初始化日志、处理命令行参数、并对参数进行初步检查，并进入运行文件夹
. "$JUDGE_UTILS/check_helper.sh"

touch program.meta program.err

mkdir -m 0777 -p feedback
# 将测试数据文件夹（内含输入数据，且其中 testdata.in 为标准输入数据文件名），编译好的程序，运行文件夹通过 overlayfs 绑定

IFS=':' read -ra SOURCE_FILES_SPLITTED <<< "$SOURCE_FILES"
IFS=':' read -ra ASSIST_FILES_SPLITTED <<< "$ASSIST_FILES"

# 假如 SOURCE_FILES 为 a.cpp:b.cpp:c.hpp，那么 SRC, INC 为 $WORKDIR/compile/a.cpp $WORKDIR/compile/b.cpp
SRC=()
INC=()
for i in "${SOURCE_FILES_SPLITTED[@]}"; do
    if [[ "$i" == *.c* ]]; then
        SRC+=("$WORKDIR/compile/$i")
    else
        INC+=(-I); INC+=("$WORKDIR/compile/$i")
    fi
done

for i in "${ASSIST_FILES_SPLITTED[@]}"; do INC+=(-I); INC+=("$WORKDIR/compile/$i"); done

# oclint 是安全的，不需要挂载也可以完成评测
runcheck $GAINROOT "$RUNGUARD" ${DEBUG:+-v} $CPUSET_OPT $MEMLIMIT_OPT $FILELIMIT_OPT $PROCLIMIT_OPT \
    --user "$RUNUSER" \
    --group "$RUNGROUP" \
    "$OPTTIME" "$TIMELIMIT" \
    --standard-error-file program.err \
    --standard-output-file oclint.json \
    --out-meta program.meta -- \
    oclint "${SRC[@]}" --report-type=json --disable-rule=ShortVariableName -- -c "${INC[@]}"

chmod 555 oclint.json

# RUNDIR 还剩下 program.meta, program.err, system.out 供评测客户端检查
# RUNDIR 由评测客户端删除

# 检查是否编译器出错/runguard 崩溃
if [ ! -s program.meta ]; then
    echo "Runguard exited with code $exitcode and 'program.meta' is empty, it likely crashed."
    cleanexit ${E_INTERNAL_ERROR:--1}
fi

if grep -E '^internal-error: .+$' program.meta >/dev/null 2>&1; then
    echo "Internal Error"
    cleanexit ${E_INTERNAL_ERROR:-1}
fi

echo "Checking program run status"
read_metadata program.meta

if grep '^time-result: .*timelimit' program.meta >/dev/null 2>&1; then
    echo "Time Limit Exceeded"
    echo "$resource_usage"
    cleanexit ${E_TIME_LIMIT:-1}
fi

if grep -E '^output-truncated: ([a-z]+,)*stdout(,[a-z]+)*' program.meta >/dev/null 2>&1; then
    echo "Output Limit Exceeded"
    echo "$resource_usage"
    cleanexit ${E_OUTPUT_LIMIT:-1}
fi

# 脚本将读入 oclint.json 并生成 report.txt 和 score.txt
runcheck python3 "$PROGDIR/process.py" oclint.json feedback/report.txt feedback/score.txt
case $exitcode in
    $RESULT_AC)
        echo "Accepted"
        echo "$resource_usage"
        cleanexit ${E_ACCEPTED:-1}
        ;;
    $RESULT_WA)
        echo "Wrong Answer"
        echo "$resource_usage"
        cleanexit ${E_WRONG_ANSWER:-1}
        ;;
    $RESULT_PC)
        echo "Partial Correct"
        echo "$resource_usage"
        cleanexit ${E_PARTIAL_CORRECT:-1}
        ;;
    *)
        echo "Comparing failed with exitcode $exitcode"
        cleanexit ${E_INTERNAL_ERROR:-1}
        ;;
esac
